package com.qianguo.shop.widget;

import android.annotation.TargetApi;
import android.content.Context;
import android.content.res.ColorStateList;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.os.Build;
import android.text.Layout;
import android.text.StaticLayout;
import android.text.TextPaint;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.widget.FrameLayout;

import com.eva.androidlibrary.widget.mdedittext.MaterialEditText;
import com.qianguo.shop.R;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * Created by eva on 15/10/18.
 */
//TODO
public class TextFieldView extends FrameLayout {

    /** 文字对齐方式 */
    /** 靠左对齐 */
    public static final int FIELD_ALIGN_LEFT = 0x1;
    /** 靠右对齐 */
    public static final int FIELD_ALIGN_RIGHT = 0x2;
    /** 两端对齐 */
    public static final int FIELD_ALIGN_JUSTIFY = FIELD_ALIGN_LEFT | FIELD_ALIGN_RIGHT;
    /** 水平居中 */
    public static final int FIELD_ALIGN_CENTER_HORIZONTAL = 0x4;
    /** 靠顶部对齐 */
    public static final int FIELD_ALIGN_TOP = 0x10;
    /** 靠底部对齐 */
    public static final int FIELD_ALIGN_BOTTOM = 0x20;
    /** 垂直居中 */
    public static final int FIELD_ALIGN_CENTER_VERTICAL = 0x40;
    /** 居中 */
    public static final int FIELD_ALIGN_CENTER = FIELD_ALIGN_CENTER_HORIZONTAL
            | FIELD_ALIGN_CENTER_VERTICAL;

    private static final int FIELD_ALIGN_HORIZONTAL_MASK = 0x7;
    private static final int FIELD_ALIGN_VERTICAL_MASK = 0x70;

    //绘制文字的画笔
    private TextPaint mPaint;
    //标签文字
    private CharSequence mLabelText = null;
    //值文字
    private CharSequence mValueText = null;
    //标签文字颜色
    private ColorStateList mLabelTextColor = null;
    //值文字颜色
    private ColorStateList mValueTextColor = null;
    //标签文字尺寸
    private float mLabelTextSize = 0.0f;
    //值文字尺寸
    private float mValueTextSize = 0.0f;
    //标签对齐方式
    private int mLabelTextAlign = FIELD_ALIGN_TOP | FIELD_ALIGN_CENTER_VERTICAL;
    //值对齐方式
    private int mValueTextAlign = FIELD_ALIGN_RIGHT | FIELD_ALIGN_CENTER_VERTICAL;
    //标签宽度
    private int mLabelLength = 0;
    //标签区域
    private Rect mLabelRect = new Rect();
    //值区域
    private Rect mValueRect = new Rect();

    private StaticLayout mLayout = null;
    
    private Value mValue = new Value();
    
    private static class Value {
        
        private int lastSetValueType;
        
        private static final int LAST_SET_INT = 1;
        private static final int LAST_SET_LONG = 2;
        private static final int LAST_SET_SHORT = 3;
        private static final int LAST_SET_FLOAT = 4;
        private static final int LAST_SET_DOUBLE = 5;
        private static final int LAST_SET_DATE = 6;
        private static final int LAST_SET_STR = 7;
        
        private int intValue;
        private float floatValue;
        private double doubleValue;
        private Date dateValue;
        private long longValue;
        private short shortValue;
        private CharSequence stringValue;
        
        private String format = null;
        
        void setString(CharSequence v) {
            this.lastSetValueType = LAST_SET_STR;
            String s = v.toString();
            this.intValue = Integer.parseInt(s);
            this.longValue = Long.parseLong(s);
            this.shortValue = Short.parseShort(s);
            this.floatValue = Float.parseFloat(s);
            this.doubleValue = Double.parseDouble(s);
            try {
                if (this.format != null) {
                    SimpleDateFormat df = new SimpleDateFormat(this.format);
                    this.dateValue = df.parse(s);
                } else {
                    SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd");
                    this.dateValue = df.parse(s);
                }
            } catch (ParseException e) {
                e.printStackTrace();
            }
            this.stringValue = v;
        }
        
        void setInt(int v) {
            this.lastSetValueType = LAST_SET_INT;
            this.intValue = v;
            this.longValue = v;
            this.floatValue = v;
            this.doubleValue = v;
            this.shortValue = (short) v;
            if (this.dateValue == null) {
                this.dateValue = new Date();
            }
            this.dateValue.setTime(this.longValue);
            if (this.format != null) {
                this.stringValue = String.format(this.format, this.intValue);
            } else {
                this.stringValue = Integer.toString(this.intValue);
            }
        }
        
        void setFloat(float v) {
            this.lastSetValueType = LAST_SET_FLOAT;
            this.intValue = (int) v;
            this.longValue = (long) v;
            this.floatValue = v;
            this.doubleValue = v;
            this.shortValue = (short) v;
            if (this.dateValue == null) {
                this.dateValue = new Date();
            }
            this.dateValue.setTime(this.longValue);
            if (this.format != null) {
                this.stringValue = String.format(this.format, this.floatValue);
            } else {
                this.stringValue = Float.toString(this.floatValue);
            }
        }
        
        void setDouble(double v) {
            this.lastSetValueType = LAST_SET_LONG;
            this.intValue = (int) v;
            this.longValue = (long) v;
            this.floatValue = (float) v;
            this.doubleValue = v;
            this.shortValue = (short) v;
            if (this.dateValue == null) {
                this.dateValue = new Date();
            }
            this.dateValue.setTime(this.longValue);
            if (this.format != null) {
                this.stringValue = String.format(this.format, this.doubleValue);
            } else {
                this.stringValue = Double.toString(doubleValue);
            }
        }
        
        void setLong(long v) {
            this.lastSetValueType = LAST_SET_LONG;
            this.intValue = (int) v;
            this.longValue = v;
            this.floatValue = v;
            this.doubleValue = v;
            this.shortValue = (short) v;
            if (this.dateValue == null) {
                this.dateValue = new Date();
            }
            this.dateValue.setTime(this.longValue);
            if (this.format != null) {
                this.stringValue = String.format(this.format, this.longValue);
            } else {
                this.stringValue = Long.toString(this.longValue);
            }
        }
        
        void setShort(short v) {
            this.lastSetValueType = LAST_SET_SHORT;
            this.intValue = v;
            this.longValue = v;
            this.floatValue = v;
            this.doubleValue = v;
            this.shortValue = v;
            if (this.dateValue == null) {
                this.dateValue = new Date();
            }
            this.dateValue.setTime(this.longValue);
            if (this.format != null) {
                this.stringValue = String.format(this.format, this.shortValue);
            } else {
                this.stringValue = Short.toString(this.shortValue);
            }
        }
        
        void setDate(Date v) {
            this.lastSetValueType = LAST_SET_DATE;
            this.dateValue = v;
            if (this.dateValue == null) {
                this.intValue = 0;
                this.longValue = 0l;
                this.floatValue = 0f;
                this.doubleValue = 0f;
                this.shortValue = 0;
            } else {
                this.longValue = this.dateValue.getTime();
                this.intValue = (int) this.longValue;
                this.shortValue = (short) this.longValue;
                this.floatValue = this.longValue;
                this.doubleValue = this.longValue;
            }
            if (this.format != null) {
                SimpleDateFormat df = new SimpleDateFormat(this.format);
                this.stringValue = df.format(this.dateValue);
            } else {
                SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd");
                this.stringValue = df.format(this.dateValue);
            }
        }
        
        void formatValue(String format) {
            this.format = format;
            if (this.format != null) {
                switch (lastSetValueType) {
                    case LAST_SET_INT:
                        this.stringValue = String.format(this.format, this.intValue);
                        break;
                    case LAST_SET_LONG:
                        this.stringValue = String.format(this.format, this.longValue);
                        break;
                    case LAST_SET_SHORT:
                        this.stringValue = String.format(this.format, this.shortValue);
                        break;
                    case LAST_SET_FLOAT:
                        this.stringValue = String.format(this.format, this.floatValue);
                        break;
                    case LAST_SET_DOUBLE:
                        this.stringValue = String.format(this.format, this.doubleValue);
                        break;
                    case LAST_SET_DATE:
                        SimpleDateFormat df = new SimpleDateFormat(this.format);
                        this.stringValue = df.format(this.dateValue);
                        break;
                    default:
                        this.stringValue = String.format(this.format, this.stringValue);
                }
            }
        }

        @Override
        public String toString() {
            return stringValue.toString();
        }
    }

    public TextFieldView(Context context) {
        super(context);
        init(context, null);
    }

    public TextFieldView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(context, attrs);
    }

    public TextFieldView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(context, attrs);
    }

    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    public TextFieldView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
        init(context, attrs);
    }

    private void init(Context context, AttributeSet attrs) {
        mPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG);
        final float DEF_TEXT_SIZE = 14.0f * getResources().getDisplayMetrics().density;
        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.TextFieldView);
        final int n = a.getIndexCount();
        for (int i = 0; i < n; i++) {
            final int index = a.getIndex(i);
            switch (index) {
                case R.styleable.TextFieldView_field_labelText:
                    mLabelText = a.getText(i);
                    break;
                case R.styleable.TextFieldView_field_valueText:
                    mValueText = a.getText(i);
                    break;
                case R.styleable.TextFieldView_field_labelTextSize:
                    mLabelTextSize = a.getDimension(i, DEF_TEXT_SIZE);
                    break;
                case R.styleable.TextFieldView_field_valueTextSize:
                    mValueTextSize = a.getDimension(i, DEF_TEXT_SIZE);
                    break;
                case R.styleable.TextFieldView_field_labelTextColor:
                    mLabelTextColor = a.getColorStateList(i);
                    break;
                case R.styleable.TextFieldView_field_valueTextColor:
                    mValueTextColor = a.getColorStateList(i);
                    break;
                case R.styleable.TextFieldView_field_labelTextAlign:
                    mLabelTextAlign = a.getInt(i, FIELD_ALIGN_LEFT | FIELD_ALIGN_CENTER_VERTICAL);
                    break;
                case R.styleable.TextFieldView_field_valueTextAlign:
                    mValueTextAlign = a.getInt(i, FIELD_ALIGN_RIGHT | FIELD_ALIGN_CENTER_VERTICAL);
                    break;
                case R.styleable.TextFieldView_fleld_labelLength:
                    mLabelLength = a.getInteger(i, 0);
                    break;
            }
        }
        a.recycle();

        if (mLabelTextColor == null) {
            mLabelTextColor = ColorStateList.valueOf(Color.BLACK);
        }
        if (mValueTextColor == null) {
            mValueTextColor = ColorStateList.valueOf(Color.BLACK);
        }
        if (mLabelTextSize == 0.0f) {
            mLabelTextSize = DEF_TEXT_SIZE;
        }
        if (mValueTextSize == .0f) {
            mValueTextSize = DEF_TEXT_SIZE;
        }
    }

    public void setValueTextFormat(String format) {
        mValue.formatValue(format);
        setValueText(mValue.toString());
    }

    public void setValue(int value) {
        mValue.setInt(value);
        setValueText(mValue.toString());
    }

    public void setValue(double value) {
        mValue.setDouble(value);
        setValueText(mValue.toString());
    }

    public void setValue(float value) {
        mValue.setFloat(value);
    }

    public void setValue(Date date) {
        mValue.setDate(date);
        setValueText(mValue.toString());
    }

    public void setValue(CharSequence value) {
        mValue.setString(value);
        setValueText(mValue.toString());
    }

    public void setValue(long value) {
        mValue.setLong(value);
        setValueText(mValue.toString());
    }
    
    public void setValue(short value) {
        mValue.setShort(value);
        setValueText(mValue.toString());
    }

    public int getValueAsInt() {
        return mValue.intValue;
    }

    public float getValueAsFloat() {
        return mValue.floatValue;
    }

    public double getValueAsDouble() {
        return mValue.doubleValue;
    }

    public Date getValueAsDate() {
        return mValue.dateValue;
    }

    public CharSequence getValueAsString() {
        return mValue.stringValue;
    }

    public long getValueAsLong() {
        return mValue.longValue;
    }
    
    public short getValueAsShort() {
        return mValue.shortValue;
    }

    /**
     * 设置标签文字
     * @param label 标签
     */
    public void setLabelText(CharSequence label) {
        mLabelText = label;
        update(true);
    }

    /**
     * 设置值的文字
     * @param value 值
     */
    public void setValueText(CharSequence value) {
        mValueText = value;
        update(true);
    }

    /**
     * 设置字段的标签和值的文字尺寸
     * @param size 尺寸
     */
    public void setFieldTextSize(float size) {
        final float DENSITY = getResources().getDisplayMetrics().density;
        mLabelTextSize = size * DENSITY;
        mValueTextSize = size * DENSITY;
        update(true);
    }

    /**
     * 设置标签文字尺寸
     * @param size 尺寸
     */
    public void setLabelTextSize(float size) {
        final float DENSITY = getResources().getDisplayMetrics().density;
        mLabelTextSize = size * DENSITY;
        update(true);
    }

    /**
     * 设置值的文字尺寸
     * @param size 尺寸
     */
    public void setValueTextSize(float size) {
        final float DENSITY = getResources().getDisplayMetrics().density;
        mValueTextSize = size * DENSITY;
        update(true);
    }

    /**
     * 设置字段的标签和值的文字颜色
     * @param color
     */
    public void setFieldTextColor(int color) {
        this.setFieldTextColor(ColorStateList.valueOf(color));
    }

    public void setFieldTextColor(ColorStateList color) {
        mLabelTextColor = color;
        mValueTextColor = color;
        update(false);
    }

    /**
     * 设置标签文字颜色
     * @param color 颜色
     */
    public void setLabelTextColor(int color) {
        this.setLabelTextColor(ColorStateList.valueOf(color));
    }

    public void setLabelTextColor(ColorStateList color) {
        mLabelTextColor = color;
        update(false);
    }

    /**
     * 设置值的文字颜色
     * @param color 颜色
     */
    public void setValueTextColor(int color) {
        this.setValueTextColor(ColorStateList.valueOf(color));
    }

    public void setValueTextColor(ColorStateList color) {
        mValueTextColor = color;
        update(false);
    }

    /**
     * 设置标签文字的对齐方式
     * @param align 对齐方式
     */
    public void setLabelTextAlign(int align) {
        mLabelTextAlign = align;
    }

    /**
     * 设置值的文字的对齐方式
     * @param align
     */
    public void setValueTextAlign(int align) {
        mValueTextAlign = align;
    }

    /**
     * 设置字段标签的宽度
     * @param length 用字体个数描述宽度
     */
    public void setLabelLength(int length) {
        if (mLabelLength != length) {
            mLabelLength = length;
            update(true);
        }
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);

        final int paddingVertical = getPaddingTop() + getPaddingBottom();
        final int paddingHorizontal = getPaddingLeft() + getPaddingRight();

        int labelWidth = 0;
        if (!TextUtils.isEmpty(mLabelText)) {
            mPaint.setTextSize(mLabelTextSize);
            final int length = mLabelText.length();
            int maxTextWidth = 0;
            char[] tempText = new char[1];
            mPaint.getTextBounds(mLabelText.toString(), 0, mLabelText.length(), mLabelRect);
            for (int i = 0; i < length; i++) {
                tempText[0] = mLabelText.charAt(i);
                maxTextWidth = Math.max((int) mPaint.measureText(tempText, 0, 1), maxTextWidth);
            }
            if (mLabelLength > 0) {
                labelWidth = mLabelLength * maxTextWidth;
            } else {
                labelWidth = mLabelText.length() * maxTextWidth;
            }
            mLabelRect.right = mLabelRect.left + (int) labelWidth;
        } else {
            // 清除区域
            mLabelRect.left = mLabelRect.top = mLabelRect.right = mLabelRect.bottom = 0;
        }


        if (!TextUtils.isEmpty(mValueText)) {
            int measuredWidth = getMeasuredWidth();
            int valueExpireWidth = measuredWidth - paddingHorizontal - labelWidth;
            valueExpireWidth = Math.min(valueExpireWidth, (int) mPaint.measureText(
                    mValueText, 0, mValueText.length()));
            if (mLayout == null) {
                mLayout = new StaticLayout(mValueText, mPaint, valueExpireWidth,
                        Layout.Alignment.ALIGN_NORMAL, 1.2f, 0.0f, false);
            }
            mValueRect.right = mValueRect.left + mLayout.getWidth();
            mValueRect.bottom = mValueRect.top + mLayout.getHeight();
        } else {
            // 清除区域
            mValueRect.left = mValueRect.top = mValueRect.right = mValueRect.bottom = 0;
        }

        final int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        final int widthSize = MeasureSpec.getSize(widthMeasureSpec);
        int measuredWidth = 0;
        switch (widthMode) {
            case MeasureSpec.EXACTLY:
                measuredWidth = widthSize;
                break;
            case MeasureSpec.AT_MOST:
                measuredWidth = Math.min(widthSize,
                        mValueRect.width() + mLabelRect.width() + paddingHorizontal);
                break;
            case MeasureSpec.UNSPECIFIED:
                measuredWidth = mValueRect.width() + mLabelRect.width() + paddingHorizontal;
                break;
        }

        final int heightMode = MeasureSpec.getMode(heightMeasureSpec);
        final int heightSize = MeasureSpec.getSize(heightMeasureSpec);
        int measuredHeight = 0;
        switch (heightMode) {
            case MeasureSpec.EXACTLY:
                measuredHeight = heightSize;
                break;
            case MeasureSpec.AT_MOST:
                measuredHeight = Math.min(heightSize,
                        Math.max(mValueRect.height() + paddingVertical,
                                mLabelRect.height() + paddingVertical));
                break;
            case MeasureSpec.UNSPECIFIED:
                measuredHeight = Math.max(mValueRect.height(), mLabelRect.height()) + paddingVertical;
                break;
        }

        setMeasuredDimension(measuredWidth, measuredHeight);
    }

    @Override
    protected void dispatchDraw(Canvas canvas) {
        super.dispatchDraw(canvas);

        final int width = getMeasuredWidth() - getPaddingLeft() - getPaddingRight();
        final int height = getMeasuredHeight() - getPaddingTop() - getPaddingBottom();
        final TextPaint paint = mPaint;
        final int labelAlign = mLabelTextAlign;
        final int valueAlign = mValueTextAlign;
        final Rect labelRect = mLabelRect;
        final Rect valueRect = mValueRect;
        final CharSequence labelText = mLabelText;
        final CharSequence valueText = mValueText;
        final ColorStateList labelColor = mLabelTextColor;
        final ColorStateList valueColor = mValueTextColor;
        float textStartY = 0.0f;
        float textStartX = 0.0f;
        int saveCount;

        // 绘制标签
        // 根据控件当前的状态获取相应的颜色
        if (TextUtils.isEmpty(labelText)) {
            paint.setColor(labelColor.getColorForState(getDrawableState(), labelColor.getDefaultColor()));
            saveCount = canvas.save();
            switch (labelAlign & FIELD_ALIGN_HORIZONTAL_MASK) {
                case FIELD_ALIGN_LEFT:
                    textStartX = 0.0f;
                    paint.setTextAlign(Paint.Align.LEFT);
                    break;
                case FIELD_ALIGN_RIGHT:
                    textStartX = labelRect.width();
                    paint.setTextAlign(Paint.Align.RIGHT);
                    break;
                case FIELD_ALIGN_CENTER_HORIZONTAL:
                    textStartX = labelRect.width() / 2;
                    paint.setTextAlign(Paint.Align.CENTER);
                    break;
                case FIELD_ALIGN_JUSTIFY:
                    // TODO
                    break;
            }
            switch (labelAlign & FIELD_ALIGN_VERTICAL_MASK) {
                case FIELD_ALIGN_TOP:
                    textStartY = valueRect.height();
                    break;
                case FIELD_ALIGN_BOTTOM:
                    textStartY = height;
                    break;
                case FIELD_ALIGN_CENTER_VERTICAL:
                    textStartY = (height + valueRect.height()) * 0.5f;
                    break;
            }
            canvas.drawText(labelText, 0, labelText.length(), textStartX, textStartY, paint);
            canvas.restoreToCount(saveCount);
        }
        
        // 绘制值
        if (TextUtils.isEmpty(valueText)) {
            return;
        }

        paint.setColor(valueColor.getColorForState(getDrawableState(), valueColor.getDefaultColor()));
        saveCount = canvas.save();
        canvas.translate(labelRect.width(), 0);
        switch (valueAlign & FIELD_ALIGN_HORIZONTAL_MASK) {
            case FIELD_ALIGN_LEFT:
                // do nothing
                break;
            case FIELD_ALIGN_RIGHT:
                canvas.translate(width - mLayout.getWidth(), 0);
                break;
            case FIELD_ALIGN_CENTER_HORIZONTAL:
                canvas.translate((width - mLayout.getWidth()) / 2, 0);
                break;
        }
        switch (valueAlign & FIELD_ALIGN_VERTICAL_MASK) {
            case FIELD_ALIGN_TOP:
                // do nothing
                break;
            case FIELD_ALIGN_BOTTOM:
                canvas.translate(0, height - mLayout.getHeight());
                break;
            case FIELD_ALIGN_CENTER_VERTICAL:
                canvas.translate(0, (height - mLayout.getHeight()) / 2);
                break;
        }
        mLayout.draw(canvas);
        canvas.restoreToCount(saveCount);
    }

    /**
     * 刷新控件内容
     * @param needRemeasure true 表示重新计算控件的尺寸，布局，否则，仅仅重绘控件
     */
    private void update(boolean needRemeasure) {
        if (needRemeasure) {
            requestLayout();
        } else {
            postInvalidate();
        }
    }
}
